package ink.xiaobaibai.serviceOxy.onePay.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import ink.xiaobaibai.bo.DeviceMqttBo;
import ink.xiaobaibai.bo.DeviceOpenInfoBo;
import ink.xiaobaibai.entity.OxygenDevice;
import ink.xiaobaibai.entity.OzoneDevice;
import ink.xiaobaibai.entity.OzonePrice;
import ink.xiaobaibai.enumOxy.DeviceStatus;
import ink.xiaobaibai.service.IOxygenDeviceService;
import ink.xiaobaibai.service.IOzoneDeviceService;
import ink.xiaobaibai.service.IOzonePriceService;
import ink.xiaobaibai.serviceOxy.IMqttService;
import ink.xiaobaibai.serviceOxy.IRedisUtils;
import ink.xiaobaibai.serviceOxy.onePay.IDelayCloseService;
import ink.xiaobaibai.serviceOxy.onePay.IDeviceOxygenControlService;
import ink.xiaobaibai.serviceOxy.onePay.IDeviceOzoneControlService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * @description: 设备控制实现类
 * @author: 小白白
 * @create: 2021-05-21
 **/

@Service
@Slf4j
public class DeviceOzoneControlServiceImpl implements IDeviceOzoneControlService {

    @Autowired
    private IOzoneDeviceService ozoneDeviceService;

    @Autowired
    private IDelayCloseService delayCloseService;

    @Autowired
    private IDeviceOxygenControlService deviceOxygenControlService;

    @Autowired
    private IMqttService mqttService;

    @Autowired
    private IOzonePriceService priceService;

    @Autowired
    private IRedisUtils redisUtils;

    @Autowired
    private IOxygenDeviceService oxygenDeviceService;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = RuntimeException.class)
    public boolean openDeviceByOnePay(Integer deviceId, String orderId) {
        /**
         * 既然付钱后启动了,说明机器没问题,有问题就应该拦截在扫码后 付钱之前
         */
        //这一步比较关键: 臭氧机器码+臭氧的四个参数氧气机状态+氧气机械码
        DeviceOpenInfoBo deviceOpenInfo = this.getDeviceOpeInfo(deviceId);

        String timeStr = this.redisUtils.getOnePatFunctionTime(orderId);
        Integer workTime;
        if (timeStr == null) {
            QueryWrapper<OzoneDevice> q1 = new QueryWrapper<>();
            q1.select("price_id");
            q1.eq("id", deviceId);
            Integer priceId = this.ozoneDeviceService.getOne(q1).getPriceId();
            OzonePrice ozonePrice = this.priceService.getById(priceId);
            workTime = ozonePrice.getTwoTime();
        } else {
            workTime = Integer.parseInt(timeStr);
        }
        //臭氧指令 此指令需要传送四个时间参数 启动延时 风扇延时 阀门延时 工作时间
        this.mqttService.openDevice(deviceOpenInfo.getOzoneDeviceCode(), this.openInfoConvertOpen(deviceOpenInfo, workTime, true));
        //发送氧气机启动指令 氧气机的工作时间= 就是自己的工作时间
        this.deviceOxygenControlService.openOxygenDevice(this.openInfoConvertOpen(deviceOpenInfo,
                workTime, false));

        this.updateDeviceWorkStopTime(deviceId, DateUtils.addSeconds(new Date(), workTime + deviceOpenInfo.getOzoneDelayedTime()),
                DeviceStatus.INUSE);
        //修改臭氧机器状态为使用中
        return true;
    }

    @Override
    public boolean closeDeviceOnePay(Integer deviceId, String orderIdOrMsg) {
//        DeviceOpenInfoBo deviceOpeInfo = this.getDeviceOpeInfo(deviceId);
        //发送臭氧机关闭信息(终端自动关闭)
        //mqttService.closeDeviceOzone(deviceOpeInfo.getOzoneDeviceCode());
        //修改臭氧机状态
//        this.updateStatus(deviceId,DeviceStatus.FREE);
        /**
         * 关闭前需要判断,当前机器状态是否为使用中,非使用中,说明已经转为故障/停运 不可再转为空闲状态
         */
        UpdateWrapper<OzoneDevice> u1 = new UpdateWrapper<>();
        u1.set("status", DeviceStatus.FREE.getStatus());
        u1.eq("id", deviceId);
        u1.eq("status", DeviceStatus.INUSE.getStatus());
        if (!this.ozoneDeviceService.update(u1)) {
            QueryWrapper<OzoneDevice> q1 = new QueryWrapper<>();
            q1.select("status");
            q1.eq("id", deviceId);
            log.error("延时成为空闲机器时,机器状态已经发送了改变,成为空闲机器时间,当前状态:" + this.ozoneDeviceService.getOne(q1).getStatus());
            return false;
        }
        //因为是客户启动,所以制氧机终端会自动关闭,并且臭氧机也会自动关闭(到点就关闭)
        //deviceOxygenControlService.closeOxygenDevice()
        return true;
    }

    /**
     * 管理员启动,能进入管理员启动的,就说明当前机器是空闲状态
     *
     * @param deviceId
     * @param seconds
     * @return
     */
    @Override
    public boolean openDeviceByAdmin(Integer deviceId, Integer seconds) {
        /**
         * 当前机器必定为空闲状态,现在要将其进行启动
         */
        DeviceOpenInfoBo deviceOpeInfo = this.getDeviceOpeInfo(deviceId);
        //臭氧机器开启接口
        this.mqttService.openDevice(deviceOpeInfo.getOzoneDeviceCode(), this.openInfoConvertOpen(deviceOpeInfo, seconds, true));
        //调用氧气机开启接
        this.deviceOxygenControlService.openOxygenDevice(this.openInfoConvertOpen(deviceOpeInfo,
                seconds, false));
        //定时关闭的延时消息
//        delayCloseService.add(deviceId,seconds,"后台开启");
        this.updateDeviceWorkStopTime(deviceId, DateUtils.addSeconds(new Date(), seconds), DeviceStatus.INUSE);
        return true;
    }

    @Override
    public boolean closeDeviceByAdmin(Integer deviceId, DeviceStatus deviceStatus) {
        /**
         * 停运和故障,需要紧急处理
         */
        QueryWrapper<OzoneDevice> q1 = new QueryWrapper<>();
        q1.select("status", "device_code", "work_stop_time", "oxygen_id");
        q1.eq("id", deviceId);
        OzoneDevice ozoneDevice = this.ozoneDeviceService.getOne(q1);

        //停运和FREE都走这里
        this.updateStatus(deviceId, deviceStatus);

        //当前正在正在运行,那么就要去将其关闭,并且移除队列
        if (ozoneDevice.getWorkStopTime().getTime() > System.currentTimeMillis()) {
            //移除队列
//            delayCloseService.remove(deviceId);
            //修改运行时间
            this.updateDeviceWorkStopTime(deviceId, new Date(), deviceStatus);
            //mqtt发送信号
            this.mqttService.closeDevice(ozoneDevice.getDeviceCode());
        }
        //当前臭氧对应的氧气旗下还有没有臭氧在工作?
        QueryWrapper<OzoneDevice> q2 = new QueryWrapper<>();
        q2.gt("work_stop_time", new Date());
        q2.eq("oxygen_id", ozoneDevice.getOxygenId());
        if (this.ozoneDeviceService.count(q2) == 0) {
            QueryWrapper<OxygenDevice> q3 = new QueryWrapper<>();
            q3.select("device_code");
            q3.eq("id", ozoneDevice.getOxygenId());
            this.deviceOxygenControlService.closeOxygenDevice(this.oxygenDeviceService.getOne(q3).getDeviceCode(), "管理员关闭");
        }
        return true;
    }

    private DeviceOpenInfoBo getDeviceOpeInfo(Integer ozoneDeviceId) {
        return this.ozoneDeviceService.getDeviceOpeInfo(ozoneDeviceId);
    }

    private void updateStatus(Integer deviceId, DeviceStatus deviceStatus) {
        UpdateWrapper<OzoneDevice> u1 = new UpdateWrapper<>();
        u1.set("status", deviceStatus.getStatus());
        u1.eq("id", deviceId);
        this.ozoneDeviceService.update(u1);
    }

    private void updateDeviceWorkStopTime(Integer deviceId, Date workStopTime, DeviceStatus deviceStatus) {
        UpdateWrapper<OzoneDevice> u1 = new UpdateWrapper<>();
        u1.set("work_stop_time", workStopTime);
        u1.set("status", deviceStatus.getStatus());
        u1.eq("id", deviceId);
        this.ozoneDeviceService.update(u1);
    }

    private DeviceMqttBo openInfoConvertOpen(DeviceOpenInfoBo deviceOpenInfo, Integer workTime, boolean isOzone) {
        if (isOzone) {
            //臭氧
            return new DeviceMqttBo(deviceOpenInfo.getOzoneDeviceCode(), true, deviceOpenInfo.getOzoneDelayedTime(), deviceOpenInfo.getOzoneFanTime(), deviceOpenInfo.getOzoneValveTime(), workTime);
        } else {
            return new DeviceMqttBo(deviceOpenInfo.getOxygenDeviceCode(), true, deviceOpenInfo.getOxygenDelayedTime(), deviceOpenInfo.getOxygenFanTime(), deviceOpenInfo.getOxygenValveTime(), workTime);
        }
    }

}
